package com.tank.net;

import com.tank.net.msg.TankDieMsg;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * @author CaoBaoYin
 * @since 2021/10/27 7:33
 */
public class Server {
    public static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    public static void main(String[] args) throws Exception {
        new Server().serverStart();
    }

    public void serverStart() {
        // 接收客户端连接（门口迎客） 处理accept
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // 处理连接后的socket client产生的事件（服务员）
        EventLoopGroup workerGroup = new NioEventLoopGroup(2);
        // 启动类
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            ChannelFuture channelFuture = bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) // channel 类型
                    // .handler(null) // 加在了server的大面板上，以及所有链接的客户端socket
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                         // 每个客户端连上后的回调方法
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {// 通道已经初始化好了会调用
                            System.out.println(socketChannel);
                             // pipeline 管道（用来流数据） 数据流进管道 handler处理（过滤器） pipeline 可以加责任处理器handler
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new TankMsgDecoder())
                                    .addLast(new TankMsgEncoder())
                                    .addLast(new ServerChildHandler());
                        }
                    }) //socket已经连接了，加在了client端上
                    .bind(8888)
                    .sync();

            ServerFrame.INSTANCE.updateServerMsg("server started...");

            // 这行都保证服务端等待客户端连接执行下面关闭代码
            channelFuture.channel() // server 的 channel
                    .closeFuture() // 如果调用了close方法，返回值是ChannelFuture。（餐厅等着关门的）
                    .sync(); // 如果不调用close方法就一直在这等着（阻塞）
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
             // 两个group没有先后的关闭顺序
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }

        System.out.println("server stopped...");
    }
}

class ServerChildHandler extends ChannelInboundHandlerAdapter {
    private static int readCount;
     // 第一次初始化的时候，channel已经可用了
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 通道可用时，计入连接的client
        Server.clients.add(ctx.channel());

        ServerFrame.INSTANCE.setTitle("server(已连接："+ Server.clients.size() +")");
    }

    // 接收数据使用。客户端有写数据的时候，此方法调用。worker读取的数据
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ServerFrame.INSTANCE.updateServerMsg("channel read：" + readCount++);

        ServerFrame.INSTANCE.updateClientMsg(msg.toString());

        if (msg instanceof TankDieMsg) {
            Server.clients.remove(ctx.channel());
            ctx.close();
            ServerFrame.INSTANCE.setTitle("server(已连接："+ Server.clients.size() +")");
        }

        Server.clients.writeAndFlush(msg);

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        Server.clients.remove(ctx.channel());
        ctx.close();// 产生异常，告诉客户端关闭的消息
    }
}
